﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AbstractTesting
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Testing test = new ManTesting();
        }
    }

    public abstract class Testing
    {
        public abstract int Kevin();

        public int DoTesting()
        {
            return 10;
        }
    }

    public class ManTesting : Testing
    {
        public override int Kevin()
        {
            return 40;
            //throw new NotImplementedException();
        }
    }

    public class PuzzlePiece
    {
        public bool FitsWith(PuzzlePiece puzzlePiece) { return true; }
        public LinkedList<PuzzlePiece> ConnectedPieces = new LinkedList<PuzzlePiece>();
    }

    public class JigsawPuzzle
    {
        LinkedList<PuzzlePiece> UnconnectedPieces = new LinkedList<PuzzlePiece>();
        Queue<PuzzlePiece> ConnectedPiecesToProcess = new Queue<PuzzlePiece>();
        PuzzlePiece FirstPiece;

        public void Solve()
        {
            if (UnconnectedPieces.First != null)
            {
                FirstPiece = UnconnectedPieces.First.Value;
                UnconnectedPieces.RemoveFirst();
                ConnectedPiecesToProcess.Enqueue(FirstPiece);

                SolveInternal();
            }
        }

        void SolveInternal()
        {
            while (ConnectedPiecesToProcess.Count > 0)
            {
                PuzzlePiece ConnectedPiece = ConnectedPiecesToProcess.Dequeue();
                LinkedListNode<PuzzlePiece> node = UnconnectedPieces.First;
                while (node != null)
                {
                    PuzzlePiece DisconnectedPiece = node.Value;
                    LinkedListNode<PuzzlePiece> tempNode = node.Next;
                    if (ConnectedPiece.FitsWith(DisconnectedPiece))
                    {
                        ConnectedPiece.ConnectedPieces.AddLast(DisconnectedPiece);
                        DisconnectedPiece.ConnectedPieces.AddLast(ConnectedPiece);
                        UnconnectedPieces.Remove(node);
                        ConnectedPiecesToProcess.Enqueue(DisconnectedPiece);
                    }

                    node = tempNode;
                }
            }
        }
    }
}
